#pragma once

#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <fstream>
#include <sstream>

#include "../comm/log.hpp"
#include "../comm/util.hpp"

namespace ns_run
{
  using namespace ns_log;
  using namespace ns_util;

  class Run
  {
  private:
    // 存储最后一次运行的时间和内存占用
    static double last_run_time;
    static long last_run_memory;

    static void SetCpuMemLimit(int cpu_ms, int mem_mb)
    {
      struct rlimit cpu;
      cpu.rlim_max = RLIM_INFINITY;
      // 将毫秒转换为秒
      cpu.rlim_cur = (cpu_ms + 999) / 1000; // 向上取整，确保至少有一秒
      setrlimit(RLIMIT_CPU, &cpu);

      struct rlimit mem;
      mem.rlim_max = RLIM_INFINITY;
      // 将MB转换为字节 (1MB = 1024 * 1024字节)
      mem.rlim_cur = (unsigned long long)mem_mb * 1024 * 1024;
      setrlimit(RLIMIT_AS, &mem);
    }

  public:
    Run() {}
    ~Run() {}

    // 获取最后一次运行的时间（毫秒）
    static std::string GetLastRunTime()
    {
      std::stringstream ss;
      ss << last_run_time << "ms";
      return ss.str();
    }

    // 获取最后一次运行的内存占用（KB）
    static std::string GetLastRunMemory()
    {
      std::stringstream ss;
      ss << last_run_memory << "KB";
      return ss.str();
    }

    static int run(const std::string &filename, const std::string &language, int cpu_size, int mem_size)
    {
      // 记录开始时间
      struct timeval start_time, end_time;
      gettimeofday(&start_time, NULL);

      pid_t pid = fork();
      if (pid < 0)
      {
        LOG(ERROR) << "创建子进程失败" << std::endl;
        return -1;
      }
      else if (pid == 0)
      {
        umask(0);
        // 重定向标准输入输出
        int stdin_fd = open(PathUtil::stdcin(filename).c_str(), O_RDONLY);
        int stdout_fd = open(PathUtil::stdcout(filename).c_str(), O_CREAT | O_WRONLY, 0644);
        int stderr_fd = open(PathUtil::stderror(filename).c_str(), O_CREAT | O_WRONLY, 0644);

        if (stdin_fd < 0 || stdout_fd < 0 || stderr_fd < 0)
        {
          LOG(ERROR) << "重定向标准输入输出失败" << std::endl;
          exit(1);
        }

        dup2(stdin_fd, 0);
        dup2(stdout_fd, 1);
        dup2(stderr_fd, 2);

        SetCpuMemLimit(cpu_size, mem_size);

        // 创建一个管道来读取程序的输出
        int pipefd[2];
        if (pipe(pipefd) == -1)
        {
          LOG(ERROR) << "创建管道失败" << std::endl;
          exit(1);
        }

        // 读取输入文件中的所有内容
        std::ifstream in(PathUtil::stdcin(filename));
        std::string input_content((std::istreambuf_iterator<char>(in)),
                                  std::istreambuf_iterator<char>());
        in.close();

        // 将输入内容写入标准输入
        write(stdin_fd, input_content.c_str(), input_content.size());
        close(stdin_fd);

        if (language == "cpp")
        {
          execl(PathUtil::exe(filename).c_str(), PathUtil::exe(filename).c_str(), nullptr);
        }
        else if (language == "python")
        {
          // 移除所有Shell重定向符号，依赖已有的文件描述符
          std::string cmd = "PYTHONUNBUFFERED=1 python3 -u " + PathUtil::src(filename, language);

          // 直接执行命令，无需重定向
          int ret = execlp("python3", "python3", "-u",
                           PathUtil::src(filename, language).c_str(), nullptr);

          if (ret == -1)
          {
            LOG(ERROR) << "执行失败，错误码: " << errno << " 错误信息: " << strerror(errno);
            exit(1);
          }
        }
        else if (language == "c")
        {
          execl(PathUtil::exe(filename).c_str(), PathUtil::exe(filename).c_str(), nullptr);
        }
        else if (language == "go")
        {
          execl(PathUtil::exe(filename).c_str(),
                PathUtil::exe(filename).c_str(), nullptr);
        }
        else
        {
          LOG(ERROR) << "不支持的语言类型: " << language << std::endl;
          exit(1);
        }

        LOG(ERROR) << "启动程序失败" << std::endl;
        exit(1);
      }
      else
      {
        int status = 0;
        struct rusage usage;
        wait4(pid, &status, 0, &usage);

        // 计算运行时间（毫秒）
        gettimeofday(&end_time, NULL);
        last_run_time = (end_time.tv_sec - start_time.tv_sec) * 1000.0 +
                        (end_time.tv_usec - start_time.tv_usec) / 1000.0;

        // 获取内存占用（KB）
        last_run_memory = usage.ru_maxrss;

        return status;
      }
    }
  };

  // 初始化静态成员变量
  double Run::last_run_time = 0.0;
  long Run::last_run_memory = 0;
}
